1

背景

最近工作中遇到了一个问题:随着项目越来越多,很多项目依赖同一个模板或是配置文件想同一管理,又不想分开维护,所以只能互相引用,或是各自维护,导致了后续的很多麻烦。

场景一: 很多公司手机端和pc同时开发,引用同一套模板,或者通用的组件库。

场景二: 用gulp、webpack来打包,或是用node来开发会有一些通用的配置文件需要统一管理。

第一阶段:gulp等自动化工具手动同步

这个是我们最初使用的方法,比如有两个项目projectA和projectB,B项目依赖A项目中的一套模板,会遇到几个问题:

  • 开发中我们引用模块的时候,B项目要经过很长的路径引用才能引到A项目中的模板,这要求所有开发者本地文件路径保持高度一致。

  • 使用webpack打包压缩静态文件的时候,A、B两个项目必须在同一个git分支,很容易搞乱。

  • 修改完文件不能及时看到效果,还要手动同步一次。这点是开发中最致命的问题,做前端的都会有体会如果改了一个样式或是一个模板要通过一个很长的操作路径才能看到效果,是非常影响开发效率的。

在用了几个月之后,各种问题暴露出来,我们必须找新的办法。

第二阶段:使用Git subtree

网上调研了很多方法,例如git submodule,第二阶段最终选择了subtree,一是官网已经不再推荐使用submodule了,二是subtree实在是太方便易用了。(后来和同事商量了下发现submodule还是有使用价值的,在第三阶段中我们再分析。)

说到subtree易用,只需要2步就可以初始化好一个子项目:

第一步:添加远程仓库

语法:git remote add -f <子仓库名> <子仓库地址>

实例:git remote add -f component git@xxx.git

验证:git remote -v 可以看到已经你添加成功了一个新的远程仓库叫 component

第二步:创建本地目录

语法:git subtree add --prefix=<子目录名> <子仓库名> <分支> --squash

实例:git subtree add --prefix=component component master --squash

这时候会在本地新建一个叫component的文件夹,--squash 会把subtree上的改动合并成一次commit

第三步:使用 ( pull & push )

pull:git subtree pull --prefix=component component master --squash

push:git subtree push --prefix=component component master --squash

注意:必须在component的父级目录执行,使用起来还不是很方便。

第四步:更方便的使用

可以在package.json里面加script语句来执行,这样在每个文件夹下都可以pull & push,强制统一,避免出错。

第三阶段:使用Git submodule

如果是引用多个子项目,会造成当前项目过于臃肿。其实有的时候类似组件库是不需要上线的,只在开发环境引用就好了。

  1. 添加:git submodule add

  2. 添加后会在当前目录下生成一个.gitmodules的新文件,里面会记录submodule的引用信息,在当前项目的位置以及仓库的url。

  3. git submodule foreach git pull 这样可以更新所有子模块。

这里只介绍了最基本的submodule用法,实际在多个项目中更新和修改submodule还是很多坑的,可以参考这篇文章 Git Submodule的坑 所以我们规定在项目中只能pull子模块,修改的话只能到子模块中去push。 这样避免了多人修改造成的冲突。

结论

在新员工加入团队时:一次性clone项目,submodule可以一起clone出来,只需添加--recursive递归参数就可以了,而subtree并不行,只能手动添加,不过可以借助神器Yeoman(一个自动生成项目脚手架的工具)来实现。

subtree适合像配置文件这种需要跟着项目走的情况。

submodule适合在开发阶段时引用,到了生产环境会被打包到指定文件内,而本身并不用跟着版本走的情况。

参考文章

  1. 官网文档:Git Tools - Subtree Merging

  2. 使用GIT SUBTREE集成项目到子目录

  3. 用 Git Subtree 在多个 Git 项目间双向同步子项目,附简明使用手册


阿驴
328 声望19 粉丝